package com.yun.zf.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yun.zf.admin.mapper.ZfCommunityMapper;
import com.yun.zf.admin.service.*;
import com.yun.zf.common.admin.domain.ZfCommunityBusiness;
import com.yun.zf.common.admin.domain.ZfDeptCommunity;
import com.yun.zf.common.admin.dto.community.*;
import com.yun.zf.common.admin.model.community.CommunityAddMo;
import com.yun.zf.common.admin.model.search.CommunityIndexKey;
import com.yun.zf.common.admin.model.search.CommunitySearchMo;
import com.yun.zf.common.app.domain.ZfCommunity;
import com.yun.zf.common.app.domain.ZfCommunitySubway;
import com.yun.zf.common.app.dto.detail.CommunityNearByDto;
import com.yun.zf.common.constant.Constants;
import com.yun.zf.common.esIndex.CommunityIndexTemplate;
import com.yun.zf.common.esRes.CommunityResMo;
import com.yun.zf.common.mapstruct.admin.CommunityMapper;
import com.yun.zf.system.alimap.BusinessAreas;
import com.yun.zf.system.exception.CustomException;
import com.yun.zf.system.service.ZfSubwayStationService;
import com.yun.zf.system.utils.AliyunOssUtil;
import com.yun.zf.system.utils.AmapUtil;
import com.yun.zf.system.utils.EsRestUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.elasticsearch.search.suggest.completion.context.CategoryQueryContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.completion.Completion;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 社区表 服务实现类
 * </p>
 *
 * @author cj
 * @since 2021-01-29
 */
@Service
@Slf4j
public class ZfCommunityServiceImpl extends ServiceImpl<ZfCommunityMapper, ZfCommunity> implements ZfCommunityService {
    @Autowired
    private AmapUtil amapUtil;
    @Autowired
    private AliyunOssUtil ossUtil;
    @Autowired
    private ZfDeptCommunityService deptCommunityService;

    @Autowired
    private ZfCommunityPictureService communityPictureService;
    @Autowired
    private ZfCommunityMapper communityMapper;
    @Autowired
    private EsRestUtil esRestUtil;
    @Autowired
    private ZfCommunitySubwayService communitySubwayService;
    @Autowired
    private ZfSchoolsService schoolsService;
    @Autowired
    private ZfCommunityBusinessService businessService;
    @Autowired
    private ZfCommunityStatisticalService statisticalService;

    @Autowired
    private ZfSubwayStationService stationService;

    @Override
    @Transactional
    public Long addBasicCommunity(String communityName, String[] city, String deptId) {
        //1、获取经纬度信息
        JSONObject jb = amapUtil.getLonLat(communityName, city[1]);
        ZfCommunity community = new ZfCommunity();
        String businessAreas=null;
        try {
            // 2、 通过经纬度获取 区域街道地址
            String regeocode = amapUtil.getAMapByLngAndLat(jb.getString("location"),"商务住宅;住宅区;住宅小区","1000","base");

            community.setProvinceCode(Long.parseLong(city[0]));
            community.setCityCode(Long.parseLong(city[1]));
            JSONObject job = JSONObject.parseObject(regeocode);
            JSONObject addressComponent = job.getJSONObject("addressComponent");
            if (addressComponent != null) {
                String provinceName = addressComponent.get("province").toString(); // 省
                String cityName = addressComponent.get("city").toString(); // 城市
                if ("[]".equals(cityName)){
                    cityName= provinceName;
                }
                String district = addressComponent.get("district").toString(); // 区域名称
                String township = addressComponent.get("township").toString(); // 街道名称
                Long adcode = Long.parseLong(addressComponent.get("adcode").toString()); // 区域代码
                Long towncode = Long.parseLong(addressComponent.get("towncode").toString()); // 街道代码
                String street = addressComponent.getJSONObject("streetNumber").get("street").toString();
                String number = addressComponent.getJSONObject("streetNumber").get("number").toString();
                businessAreas = addressComponent.getString("businessAreas");
                community.setProvinceName(provinceName);
                community.setCityName(cityName);
                community.setRegionName(district);
                community.setStreetName(township);
                community.setAddress(street + number);
                community.setRegionCode(adcode);
                community.setStreetCode(towncode);
                community.setCommunityName(communityName);
                community.setLocation(jb.getString("location"));
                community.setCStatus("ed");
            }else {
                return  -1L ;
            }

        }catch (Exception e){
        return  -1L;
        }
        // 保存小区信息
        int count = baseMapper.insert(community);
        if (count <= 0) {
            return -1L;
        }
        log.info("小区id---------" + community.getId());
        // 保存商圈信息
        List<ZfCommunityBusiness> businessList = new ArrayList<>();
        List<BusinessAreas> dataArr = JSONArray.parseArray(businessAreas, BusinessAreas.class);
        for (BusinessAreas bus:dataArr) {
            if (bus==null){
                continue;
            }
            ZfCommunityBusiness business =new ZfCommunityBusiness();
            business.setAliId( bus.getId());
            business.setBusinessName(bus.getName());
            business.setLocation(bus.getLocation());
            business.setCommunityId(community.getId());
            businessList.add(business);
        }
        businessService.addBusiness(businessList);
        // 通过小区获取1公里内的地铁站id
        JSONObject job = amapUtil.around(community.getLocation(), "", "150500", "", "1000", 20, 1, "");
        JSONArray pois = job.getJSONArray("pois");
        if (pois.size() > 0) {
            for (int i = 0; i < pois.size(); i++) {
                ZfCommunitySubway communitySubway = new ZfCommunitySubway();
                communitySubway.setStationPoi(JSONObject.parseObject(pois.get(i).toString()).get("id").toString());
                communitySubway.setCommunityId(community.getId());
                communitySubwayService.addCommunitySubway(communitySubway);
            }
        }
        // 保存 门店与小区关系，只有当前门店才可维护当前小区房源信息
        ZfDeptCommunity deptCommunity = new ZfDeptCommunity();
        deptCommunity.setCommunityId(community.getId());
        deptCommunity.setDept3Id(Long.parseLong(deptId) );
        deptCommunity.setCreateTime(new Date());
        deptCommunityService.addDeptCommunity(deptCommunity);
        return community.getId();
    }



    @Override
    public CommunityDto getCommunityById(Long communityId) {
        //1、 获取基本信息
        CommunityBasicDto basic =this.getBasic(communityId);
        List<CommunityPictureDto> pictureList = communityPictureService.getCommunityPicture(communityId,-1);
        Map<Integer, List<CommunityPictureDto>> groupBy = pictureList.stream().collect(Collectors.groupingBy(CommunityPictureDto::getType));
        CommunityDto mo= new CommunityDto();
        // 小区基本信息
        mo.setBasicDto(basic);
        // 封面图
        mo.setCover(groupBy.get(0));
        // 获取户型图
        mo.setHxPic(groupBy.get(3));
        // 小区环境图
        mo.setPictureList(groupBy.get(1));
        // 统计信息
        List<CommunityStatisticalDto>  statistical = statisticalService.getStatistical(communityId);
        mo.setStatistical(statistical);

        //3、 获取小区地铁信息
        List<CommunitySubwayDto> subwayDtoList = communitySubwayService.getSubwayList(communityId);
        mo.setSubwayDtoList(subwayDtoList);
        //4、获取对口学校信息
       List<CommunitySchoolsDto> schools= schoolsService.getCommunitySchools(communityId);
        mo.setSchools(schools);
        // 经纪人信息
        List<AgentInfoDto> agents = deptCommunityService.getAgentInfo(communityId);
        mo.setAgents(agents);
        return mo;
    }

    @Override
    public void motifyCommunity(CommunityAddMo communityAddMo) {
        QueryWrapper<ZfCommunity> communityQueryWrapper = new QueryWrapper<>();
        communityQueryWrapper.lambda().eq(ZfCommunity::getId,Long.parseLong(communityAddMo.getId()));
       ZfCommunity community = baseMapper.selectOne(communityQueryWrapper);
        BeanUtil.copyProperties(communityAddMo, community,  CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
       baseMapper.update(community,communityQueryWrapper);
    }

    /**
     * 发布小区信息到ES
     *
     * @param id
     */
    @Override
    public void publishCommunity(Long id) {
        //获取小区数据
        ZfCommunity community = this.esCommunityById(id);
        // 检测其中部分信息，如果为空，则不能进行发布
        if(StringUtils.isBlank(community.getPropertyCompany())){
        throw  new CustomException("请补充完整信息后在进行发布");
        }
        // 检测小区环境图片是否上传，不少于5张
        List<CommunityPictureDto> pictureList = communityPictureService.getCommunityPicture(id,-1);
        Map<Integer,Long> size =  pictureList.stream().collect(Collectors.groupingBy(CommunityPictureDto::getType,Collectors.counting()));
       size.forEach((k,v)->{
           if (v==0){
               throw  new CustomException("请补充完整图片信息");
           }
       });

        // 获取地铁站数据
        List<String> stations = communitySubwayService.getStationsById(id);
        // 获取小区对口学校信息
        List<String> schools = schoolsService.getSchools(id);
        // 获取商圈信息
        List<String> businessName =  businessService.getBusiness(id);

        //转换小区中的ES 信息，推送
        CommunityIndexTemplate indexTemplate = CommunityMapper.INSTANCE.communityDoIndex(community);
        indexTemplate.setCommunityStations(stations);
        indexTemplate.setEduSchools( schools);
        indexTemplate.setBusiness(businessName);
        // 将商圈+ 小区名称一起放入搜索建议词中，如果命中，则显示符合条件的小区名称
        String [] completionContext=null;
        if (businessName!=null&& businessName.size()>0){
            String[] bs = businessName.toArray(new String[businessName.size()]);
             completionContext = ArrayUtil.append(bs,community.getCommunityName());
        } else  {
            completionContext= new String[]{community.getCommunityName()};
        }
        Completion completion = new Completion(completionContext);
        Map<String, List<String>> contexts = new HashMap<>();
        List<String> list = new ArrayList<>();
        list.add(community.getCityCode().toString());
        contexts.put("city", list);
        completion.setContexts(contexts);
        indexTemplate.setCommunityNameSuggest(completion);
        try {
            // 小区信息发布必须自定义ID ,防止出现重复数据
            String esData = esRestUtil.addDataRest(indexTemplate, Constants.ES_COMMUNITY_INDEX, String.valueOf(id));

            log.info("小区消息返回数据---------" + esData);
            // 修改小区状态
            baseMapper.changeStatus(id,"on");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public ZfCommunity esCommunityById(Long communityId) {
        return baseMapper.selectById(communityId);
    }


    /**
     * 小区名称自动补全, 选择所在的城市小区自动补全
     *
     * @param text 名称
     * @return 返回id 省市区划代码，小区名称
     */
    @Override
    public List<Map<String, String>> communitySuggestToHouse(String text, Long cityCode) {
        //词项建议
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("cityCode", cityCode));
        //  sourceBuilder.query(queryBuilder);
        // 创建CompletionSuggestionBuilder
        CompletionSuggestionBuilder suggestionBuilder = SuggestBuilders.completionSuggestion("communityNameSuggest") // 指定字段名
                .size(10) // 设定返回数量
                .skipDuplicates(true)
                .analyzer("ik_smart"); // 去重
        // 配置context，选择当前城市下的小区
        CategoryQueryContext categoryQueryContext = CategoryQueryContext.builder().setCategory(cityCode.toString()).build();

        Map<String, List<? extends ToXContent>> contexts = new HashMap<>();
        List<CategoryQueryContext> list = new ArrayList<>();
        list.add(categoryQueryContext);
        contexts.put("city", list);  // 分类字段
        suggestionBuilder.contexts(contexts); // 设置contexts
        // 创建suggestBuilder并将completionBuilder添加进去
        SuggestBuilder suggestBuilder = new SuggestBuilder();
        suggestBuilder.addSuggestion("community-suggest", suggestionBuilder).setGlobalText(text);
        // 执行请求
        CompletionSuggestion suggestion = esRestUtil.termSuggest(Constants.ES_COMMUNITY_INDEX, suggestBuilder);
        //搜索结果状态信息
        List<Map<String, String>> suggestList = new ArrayList<>();
        for (CompletionSuggestion.Entry entry : suggestion.getEntries()) {
            log.info("text: " + entry.getText().string());
            for (CompletionSuggestion.Entry.Option option : entry) {
                String suggestText = option.getText().string();
                String id = option.getHit().getId();
                String provinceCode = option.getHit().getSourceAsMap().get("provinceCode").toString();
                String regionCode = option.getHit().getSourceAsMap().get("regionCode").toString();
                String streetCode = option.getHit().getSourceAsMap().get("streetCode").toString();
                Map<String, String> map = new HashMap();
                map.put("id", id);
                map.put("cityCode", cityCode.toString());
                map.put("provinceCode", provinceCode);
                map.put("suggestText", suggestText);
                map.put("regionCode", regionCode);
                map.put("streetCode", streetCode);
                suggestList.add(map);
                log.info("   suggest option : " + suggestText);
            }
        }
        return suggestList;
    }

    /**
     * 搜索框内容自动补全提示
     *
     * @param text 名称
     * @return 返回id 省市区划代码，小区名称
     */
    @Override
    public List<Map<String, String>> communitySuggest(String text, Long cityCode) {
        //词项建议
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("cityCode", cityCode));
        //  sourceBuilder.query(queryBuilder);
        // 创建CompletionSuggestionBuilder
        CompletionSuggestionBuilder suggestionBuilder = SuggestBuilders.completionSuggestion("communityNameSuggest") // 指定字段名
                .size(10) // 设定返回数量
                .skipDuplicates(true)
                .analyzer("ik_smart"); // 去重
        // 配置context，选择当前城市下的小区
        CategoryQueryContext categoryQueryContext = CategoryQueryContext.builder().setCategory(cityCode.toString()).build();

        Map<String, List<? extends ToXContent>> contexts = new HashMap<>();
        List<CategoryQueryContext> list = new ArrayList<>();
        list.add(categoryQueryContext);
        contexts.put("city", list);  // 分类字段
        suggestionBuilder.contexts(contexts); // 设置contexts
        // 创建suggestBuilder并将completionBuilder添加进去
        SuggestBuilder suggestBuilder = new SuggestBuilder();
        suggestBuilder.addSuggestion("community-suggest", suggestionBuilder).setGlobalText(text);
        // 执行请求
        CompletionSuggestion suggestion = esRestUtil.termSuggest(Constants.ES_COMMUNITY_INDEX, suggestBuilder);
        //搜索结果状态信息
        List<Map<String, String>> suggestList = new ArrayList<>();
        for (CompletionSuggestion.Entry entry : suggestion.getEntries()) {
            log.info("text: " + entry.getText().string());
            for (CompletionSuggestion.Entry.Option option : entry) {
                String suggestText = option.getText().string();
                String streetName = option.getHit().getSourceAsMap().get("streetName").toString();
                String communityName = option.getHit().getSourceAsMap().get("communityName").toString();
                // 商圈
                List<String> business = (ArrayList<String>) option.getHit().getSourceAsMap().get("business");
                if (StringUtils.isNotEmpty(suggestText)){
                    Map<String, String> map = new HashMap();
                    map.put("suggestText", suggestText);
                    if (suggestText.equals(communityName)){
                        map.put("type","C");
                        map.put("title","小区");
                        map.put("streetName",streetName);
                    }else if (business.contains(suggestText)){
                        map.put("type","B");
                        map.put("title","商圈");
                    }
                    // 如果学校也放进补全提示信息中后，就取出来与学校字段进行对比
                    suggestList.add(map);
                }
                log.info("   suggest option : " + suggestText);
            }
        }
        return suggestList;
    }

    /**
     * 搜索小区数据
     *
     * @param communitySearchMo
     */
    @Override
    public Map<String, Object> searchCommunitys(CommunitySearchMo communitySearchMo) {
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
        String[] fields = {CommunityIndexKey.CID};
        //1 、 构建搜索条件
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        // 城市代码必须
        queryBuilder.must(QueryBuilders.termQuery(CommunityIndexKey.CITYCODE, communitySearchMo.getCityCode()));
        // 区域街道代码搜索
        if (StringUtils.isNotEmpty(communitySearchMo.getRegionCode())&&!"BX".equals(communitySearchMo.getRegionCode())){
            queryBuilder.must(QueryBuilders.termQuery(CommunityIndexKey.REGIONCODE,communitySearchMo.getRegionCode()));
        }
        if (StringUtils.isNotEmpty(communitySearchMo.getStreetCode())&&!"BX".equals(communitySearchMo.getStreetCode())){
            queryBuilder.must(QueryBuilders.termQuery(CommunityIndexKey.STREETCODE,communitySearchMo.getStreetCode()));
        }

        // 如果搜索框内容不为空
        if (StringUtils.isNotBlank(communitySearchMo.getContext())) {
            if (StringUtils.isEmpty(communitySearchMo.getCommunityType())|| "C".equals(communitySearchMo.getCommunityType())){
                queryBuilder.must(QueryBuilders.matchQuery(CommunityIndexKey.COMMUNITYNAME, communitySearchMo.getContext()).boost(2.0f));
            }
            // 如果为商圈，搜索补全接口会返回是商圈或者小区
            else if ("B".equals(communitySearchMo.getCommunityType())){
                queryBuilder.must(QueryBuilders.matchQuery(CommunityIndexKey.BUSINESS, communitySearchMo.getContext()).boost(2.0f));
            }else if ("S".equals(communitySearchMo.getCommunityType())){
                queryBuilder.filter(QueryBuilders.termQuery(CommunityIndexKey.EDUSCHOOLS, communitySearchMo.getContext() ).boost(2.0f));
            }

        }

        // 如果均价区间不为空则加上均价搜索
        if (StringUtils.isNotBlank(communitySearchMo.getAveragePrice())&&!"BX".equals(communitySearchMo.getAveragePrice())) {
            String minPrice = communitySearchMo.getAveragePrice().split("-")[0];
            String maxPrice = communitySearchMo.getAveragePrice().split("-")[1];
            queryBuilder.filter(QueryBuilders.rangeQuery(CommunityIndexKey.AVERAGEPRICE).gte(minPrice).lte(maxPrice));
        }
        // 如果楼龄不为空，则获取符合条件的楼龄范围
        if (StringUtils.isNotBlank(communitySearchMo.getCtyBuildYear())&&!"BX".equals(communitySearchMo.getCtyBuildYear())) {
            int nowYear = DateUtil.thisYear();
            int minYear = nowYear - Integer.parseInt(communitySearchMo.getCtyBuildYear().split("-")[0]);
            int maxYear = nowYear - Integer.parseInt(communitySearchMo.getCtyBuildYear().split("-")[1]);
            queryBuilder.filter(QueryBuilders.rangeQuery(CommunityIndexKey.CTYBUILDYEAR).gte(maxYear).lte(minYear));
        }
        // 如果地铁线不为空
        if (StringUtils.isNotEmpty(communitySearchMo.getSubway())){
            if (communitySearchMo.getSubway().equals("BX")){
                queryBuilder.filter(QueryBuilders.existsQuery(CommunityIndexKey.COMMUNITYSTATIONS));
            }else {
                // 如果站点选择不限，则查出当前地铁线下的所有站点
                if (communitySearchMo.getStations().equals("BX")){
                    List<String> stations = stationService.getStationPois(Long.parseLong(communitySearchMo.getSubway()));
                    queryBuilder.filter(QueryBuilders.termsQuery(CommunityIndexKey.COMMUNITYSTATIONS, stations));

                }else {
                    String [] stations = communitySearchMo.getStations().split(",");
                    queryBuilder.filter(QueryBuilders.termsQuery(CommunityIndexKey.COMMUNITYSTATIONS, stations));
                }
            }
        }

        // 如果地铁站点不为空
      /*  if (StringUtils.isNotEmpty(communitySearchMo.getStations())){
            if (communitySearchMo.getStations().equals("BX")){
                queryBuilder.filter(QueryBuilders.existsQuery(CommunityIndexKey.COMMUNITYSTATIONS));
            }
            String [] stations = communitySearchMo.getStations().split(",");
            queryBuilder.filter(QueryBuilders.termsQuery(CommunityIndexKey.COMMUNITYSTATIONS, stations));
        }*/
        searchQueryBuilder.withQuery(queryBuilder).withFields(fields);
        try {
            Map<String, Object> communityData = esRestUtil.searchDataPage(Constants.ES_COMMUNITY_INDEX, communitySearchMo.getCurrent(), communitySearchMo.getPageSize(), CommunityResMo.class, searchQueryBuilder);

            return communityData;
        } catch (Exception e) {

        }

        return null;
    }

    /**
     * 获取小区基本信息
     *
     * @param
     * @return
     */
    @Override
    public List<CommunityNearByDto> getBasicCommunity(List<Long> ids) {
        List<CommunityNearByDto> list =     communityMapper.getBasicCommunity(ids);
        for (CommunityNearByDto near: list
             ) {
            List<CommunityStatisticalDto> statisticalDtos =  statisticalService.getStatistical(Long.parseLong(near.getId()));
            for (CommunityStatisticalDto cs:statisticalDtos
                 ) {
                if (cs.getType()==1){
                    near.setRentTotal(cs.getTotal());
                }else  if (cs.getType()==2){
                    near.setSoldTotal(cs.getTotal());
                    near.setAveragePrice(cs.getAveragePrice());
                }
            }

        }

        return  list;
    }

    /**
     * 根据小区ID 以及区划代码查询小区信息
     *
     * @param communityId  小区Id
     * @param provinceCode 升级区划代码
     * @param cityCode     市级区划代码
     * @return
     */
    @Override
    public ZfCommunity getCommunity(Long communityId, Long provinceCode, Long cityCode) {
        QueryWrapper<ZfCommunity> communityQueryWrapper = new QueryWrapper<>();
        communityQueryWrapper.lambda().eq(ZfCommunity::getCityCode, cityCode).eq(ZfCommunity::getProvinceCode, provinceCode).eq(ZfCommunity::getId, communityId);
        return baseMapper.selectOne(communityQueryWrapper);
    }

    @Override
    public ZfCommunity findommunityBasic(Long communityId) {
        QueryWrapper<ZfCommunity> communityQueryWrapper = new QueryWrapper<>();
        communityQueryWrapper.lambda().eq(ZfCommunity::getId, communityId);
        return baseMapper.selectOne(communityQueryWrapper);
    }

    @Override
    public void changeStatus(Long communityId ,String status ) {
        baseMapper.changeStatus(communityId,status);
    }

    @Override
    public CommunityBasicDto getBasic(Long communityId) {
        //1、 获取基本信息
        QueryWrapper<ZfCommunity> communityQueryWrapper = new QueryWrapper<>();
        communityQueryWrapper.lambda().eq(ZfCommunity::getId, communityId);
        ZfCommunity community = baseMapper.selectOne(communityQueryWrapper);
        // 数据转换
       return  CommunityMapper.INSTANCE.communityDoToMo(community);
    }
}
